package mapkit
{
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	import mapkit.carto.Envelope;
	import mapkit.carto.IMap;
	import mapkit.carto.IMapLocator;
	import mapkit.carto.Location;
	import mapkit.carto.MapLocator;
	
	import mx.containers.Canvas;
	import mx.core.UIComponent;
	
	import nl.demonsters.debugger.MonsterDebugger;

	final public class Map extends Canvas implements IMap
	{
		private var _handlers:Dictionary=new Dictionary(true);

		final public function getHandler(handlerType:Class):MapHandler
		{
			return _handlers[handlerType];
		}

		final public function enableHandler(handler:MapHandler):void
		{
			var moduleClass:Class=getDefinitionByName(getQualifiedClassName(handler)) as
				Class;
			if (!_handlers[moduleClass])
			{
				_handlers[moduleClass]=handler;
			}
			handler.start(this);
			for each (var h:MapHandler in _handlers)
			{
				if ((handler != h && handler.keyboardLocked && h.keyboardLocked) ||
					(handler != h && handler.mouseLocked && h.mouseLocked))
				{
					h.stop();
				}
			}
		}

		final public function disableHandler(handlerType:Class):void
		{
			var handler:MapHandler=_handlers[handlerType];
			if (handler)
			{
				handler.stop();
			}
		}

		final public function clearStoppedHandlers():void
		{
			for (var htype:*in _handlers)
			{
				if (!_handlers[htype].ready)
				{
					delete _handlers[htype];
				}
			}
		}

		final public function clearAllHandlers():void
		{
			for (var htype:*in _handlers)
			{
				delete _handlers[htype];
			}
		}

		private var _layers:Canvas=new Canvas();

		final public function get layers():Canvas
		{
			return _layers;
		}

		private var _acetate:Canvas=new Canvas();

		final public function get acetate():Canvas
		{
			return _acetate;
		}

		final public function addLayer(layer:MapLayer):void
		{
			layer.start(this);
			_layers.addChild(layer);
		}

		final public function removeLayer(layer:MapLayer):void
		{
			_layers.removeChild(layer);
			layer.stop();
		}

		private var _ready:Boolean=false;

		final public function get ready():Boolean
		{
			return _ready;
		}

		private var _extent_changed:Boolean=false;

		private var _extent:Envelope=new Envelope();

		final public function get extent():Envelope
		{
			return _extent;
		}

		final public function set extent(value:Envelope):void
		{
			_extent=value;
			_extent_changed=true;
			invalidateProperties();
		}

		final public function get center():Location
		{
			return extent.center;
		}

		final public function get scale():Number
		{
			return width / extent.width;
		}

		private var _size_changed:Boolean=false;

		override public function set width(value:Number):void
		{
			super.width=value;
			_size_changed=true;
			invalidateProperties();
		}

		override public function set height(value:Number):void
		{
			super.height=value;
			_size_changed=true;
			invalidateProperties();
		}

		private var _locator_changed:Boolean=false;
		private var _locator:IMapLocator=new MapLocator();

		final public function get locator():IMapLocator
		{
			return _locator;
		}

		final public function set locator(value:IMapLocator):void
		{
			_locator=value;
			_locator_changed=true;
			invalidateProperties();
		}

		final public function toMapPoint(pt:Point):Location
		{
			return _locator.toMapPoint(pt, this);
		}

		final public function fromMapPoint(loc:Location):Point
		{
			return _locator.fromMapPoint(loc, this);
		}

		private var _mask:UIComponent=new UIComponent();

		override protected function createChildren():void
		{
			super.createChildren();

			_locator=new MapLocator();

			addChild(_mask);
			mask=_mask;

			addChild(_layers);

			_acetate.percentWidth=100;
			_acetate.percentHeight=100;
			addChild(_acetate);

			horizontalScrollPolicy="off";
			verticalScrollPolicy="off";

			dispatchEvent(new MapEvent(MapEvent.READY));
			_ready=true;
		}

		override protected function commitProperties():void
		{
			super.commitProperties();

			if (_size_changed)
			{
				dispatchEvent(new MapEvent(MapEvent.SIZE_CHANGE));
			}

			if (_extent_changed)
			{
				dispatchEvent(new MapEvent(MapEvent.EXTENT_CHANGE));
			}

			if (_locator_changed)
			{
				dispatchEvent(new MapEvent(MapEvent.LOCATOR_CHANGE));
			}

			if (_size_changed || _extent_changed || _locator_changed)
			{
				dispatchEvent(new MapEvent(MapEvent.CHANGE));
				_size_changed=false;
				_extent_changed=false;
				_locator_changed=false;
			}
		}

		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);

			graphics.clear();
			graphics.beginFill(0xffffff);
			graphics.drawRect(0, 0, width, height);
			graphics.endFill();
			_mask.graphics.beginFill(0x000000);
			_mask.graphics.drawRect(0, 0, width, height);
			_mask.graphics.endFill();
		}
	}
}
